package com.wondertek.poms.pre.manager.xml2Cont;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.w3c.dom.NodeList;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.wondertek.poms.common.constant.Constants;
import com.wondertek.poms.common.exception.MessageCodes;
import com.wondertek.poms.common.utils.StringUtil;
import com.wondertek.poms.core.service.IContentService;
import com.wondertek.poms.core.service.IDisplayFileService;
import com.wondertek.poms.core.service.IMediaFileService;
import com.wondertek.poms.core.service.ISecondClassifyService;
import com.wondertek.poms.core.service.ISystemConfigService;
import com.wondertek.poms.dao.po.Content;
import com.wondertek.poms.dao.po.DisplayFile;
import com.wondertek.poms.dao.po.MediaFile;
import com.wondertek.poms.dao.po.SecondClassify;
import com.wondertek.poms.dao.po.SyncTask;
import com.wondertek.poms.pre.message.BusinessException;
import com.wondertek.poms.transform.xmlvo.ContentFromXml;
import com.wondertek.poms.transform.xmlvo.DisplayFileFromXml;
import com.wondertek.poms.transform.xmlvo.KeyWord;
import com.wondertek.poms.transform.xmlvo.Label;
import com.wondertek.poms.transform.xmlvo.MediaFileFromXml;
import com.wondertek.poms.transform.xmlvo.PropertyFile;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.XmlUtil;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * <p><b>Xml2ContentManager Description:</b> nas上xml转换为内容对象</p>
 * @author douzi
 * <b>DATE</b> 2020年12月22日 下午6:34:32
 */
@Slf4j
@Component
public class Xml2ContentManager {
    @Autowired
    private ISystemConfigService systemConfigService;
    @Autowired
    private IContentService contentService;
    @Autowired
    private IMediaFileService mediaFileService;
    @Autowired
    private ISecondClassifyService secondClassifyService;
    @Autowired
    private IDisplayFileService displayFileService;
    @Autowired
    PlayBillManager playBillManager;
	
	/**
	 * <p><b>Title:</b> process</p>
	 * <p><b>Description:</b> 主方法</p>
	 * @author douzi
	 * @throws Exception 
	 */
	public Content process(SyncTask st) throws Exception {
		Content c = new Content();
        String docStr = cleanXml(st);
        ContentFromXml cfx = tranXml(docStr);
        
        BeanUtils.copyProperties(cfx, c);
        BeanUtils.copyProperties(cfx.getCopyRight(), c);
        checkContent(st, c);
        
        setContentSpecial(st, c);
        log.info("内容同步主流程|通过ContentFromXml对象转化得到Content对象成功");
        
        //直播节目单 处理
    	playBillManager.process(c);
    	return c;
	}
	
	/**
	 * <p><b>Title:</b> setContentSpecial</p>
	 * <p><b>Description:</b> 特殊列设置；顺便保存内容对象、图片列表、二级分类、媒体文件入库</p>
	 * @author douzi
	 * @param st
	 * @param c
	 */
	private void setContentSpecial(SyncTask st, Content c) {
		c.setIsSupWap(1L);
		c.setIsSupH264(1L);
		c.setIsSupWww(1L);
		c.setIsSupRms(1L);
		c.setIsSupRchd(1L);
        c.setDisplayFileLists(st.getBasePath());
        c.setHasVideo(c.getMediaFileList() != null && c.getMediaFileList().size() > 0);
        if (StringUtil.isNullStr(c.getPreRecord())) {
            if (c.getFormType().equals("13")) {
                c.setPreRecord("0");
            } else {
                c.setPreRecord(null);
            }
        }
        //来自新媒资的内容自动设为已搬迁
        if ("89".equals(st.getAccessPlatformType())) {
            c.setHasMoved(true);
        }
        c.setUpdateFields(st.getUpdateFields());
        c.setBcPriority(st.getPriority());
        c.setAccessPlatformType(st.getAccessPlatformType());
        c.setDistResult(st.getDistResult());
        c.setStatus(Long.valueOf(Integer.parseInt(st.getOprCode()) - 1));
        //获取最后更新时间
        try {
            if (c.getLastModifyTime() == null || "".equals(c.getLastModifyTime())) {
                c.setLastModifyTime(c.getCreateTime());
            }
            String time = DateUtil.format(DateUtil.parse(c.getLastModifyTime()), "yyyyMMddHHmm");
            st.setLastModifyTime(time);
        } catch (Exception e) {
            log.error("内容同步主流程|内容:" + c.getContentId() + "|最后更新时间修改格式失败", e);
        }
        
        if (c.getLabelList() != null && c.getLabelList().size() > 0) {
            for (Iterator<Label> it = c.getLabelList().iterator(); it.hasNext(); ) {
                Label l = it.next();
                if (l != null && !StringUtil.isNullStr(l.getLabel())) {
                    if (Constants.MULTI_SCREEN_SIGN.equals(l.getLabel())) {
                        //临时判断如果标签中包含‘支持多屏续播’ 则将 isMultiScreen属性置为 true
                        c.setIsMultiScreen(true);
                    }
                    c.addLabel(l.getLabel());
                }
            }
        }
        
        if (c.getKeyWordList() != null
                && c.getKeyWordList().size() > 0) {
            for (Iterator<KeyWord> it = c.getKeyWordList().iterator(); it.hasNext(); ) {
                KeyWord kw = it.next();
                if (kw != null && kw.getKeywordName() != null) {
                    if (kw.getPrimaryKey() != null && 
                    		Constants.CONTENT_IS_PRIMARY_KEYWORD.equals(kw.getPrimaryKey())) {
                        c.addPrimaryKeyWord(kw.getKeywordName());
                    } else {
                        c.addKeyWord(kw.getKeywordName());
                    }
                }
            }
        }

        List<MediaFile> mediaFileList = new ArrayList<MediaFile>();
        if (c.getMediaFileList() != null && c.getMediaFileList().size() > 0) {
            for (MediaFileFromXml formXml : c.getMediaFileList()) {
                if (formXml != null) {
                    MediaFile mediaFile = new MediaFile();
                    if (formXml.getMediaUsageCode() != null) {
                        BeanUtils.copyProperties(formXml, mediaFile);
                        c.getMediaUsageCodeList().add(mediaFile.getMediaUsageCode());
                    }
                    mediaFile.setContentId(c.getContentId());
                    mediaFileList.add(mediaFile);
                }
            }
        }
        
        List<SecondClassify> secondClassifyList = new ArrayList<SecondClassify>();
        if (c.getPropertyFileLists() != null && c.getPropertyFileLists().size() > 0) {
        	for (PropertyFile pf : c.getPropertyFileLists()) {
        		SecondClassify sc = new SecondClassify();
        		sc.setContentId(c.getContentId());
        		sc.setClassifyKey(pf.getPropertyKey());
        		sc.setClassifyValue(pf.getPropertyValue());
        		secondClassifyList.add(sc);
			}
        }
        
        List<DisplayFile> displayFileList = new ArrayList<DisplayFile>();
        if (c.getDisplayFileList() != null && c.getDisplayFileList().size() > 0) {
            for (DisplayFileFromXml displayFileFromXml : c.getDisplayFileList()) {
                DisplayFile displayFile = new DisplayFile();
                BeanUtils.copyProperties(displayFileFromXml, displayFile);
                displayFile.setDpFilePath(st.getBasePath() + "/" + c.getContentId() + "/display/" + displayFile.getDpFileName());
                displayFileList.add(displayFile);
            }
        }
        
        log.info("主流程|内容:" + c.getContentId() + "|XML转换对象mediaFileList：" + JSONUtil.toJsonStr(mediaFileList) + 
        		"|二级分类secondClassifyList：" + JSONUtil.toJsonStr(secondClassifyList) + 
        		"|图片对象displayFileList：" + JSONUtil.toJsonStr(displayFileList));
        
        //没有转码则延续之前的转码时间
        Content tempContent = contentService.findByContentId(c.getContentId());
        if (tempContent != null && tempContent.getId() != null) {
        	c.setId(tempContent.getId());
            if (c.getLastTranscodeTime() == null) {
                c.setLastTranscodeTime(tempContent.getLastTranscodeTime());
            }
        }
        
        String fileName = st.getBasePath() + "/" + st.getContentId() + "/" + "Metadata.xml";
        c.setSyncFilePath(fileName);
        c.setContSourceStatus(1L);//内容来源于POMS
        
        contentService.save(c);
        log.info("内容同步主流程|业务数据：" + c.getContentId() + "|媒资id：" + c.getAssetId() + "入库成功");
        
        updateMediaFiles(c, mediaFileList);
        updateSecondClassifys(c, secondClassifyList);
        updateDisplayFiles(c, displayFileList);
        log.info("内容同步主流程|业务数据：" + c.getContentId() + "|媒资id：" + c.getAssetId() + "媒体文件、二级分类、图片入库成功");
	}
	
	/**
	 * <p><b>Title:</b> updateDisplayFiles</p>
	 * <p><b>Description:</b> 更新原图列表</p>
	 * @author douzi
	 * @param c
	 * @param dfs
	 */
    private void updateDisplayFiles(Content c, List<DisplayFile> dfs) {
        List<DisplayFile> list = displayFileService.findByContentId(c.getContentId());
        if (list != null && list.size() > 0) {
            displayFileService.deleteByContentId(c.getContentId());
        }
        log.info("主流程|图片存入DB：" + JSONUtil.toJsonStr(dfs));
        if (dfs != null && dfs.size() > 0) {
        	displayFileService.saveAll(dfs);
        }
    }
	
	/**
	 * <p><b>Title:</b> updateMediaFiles</p>
	 * <p><b>Description:</b> 保存媒体文件信息</p>
	 * @author douzi
	 * @param c
	 * @param mfs
	 */
    private void updateMediaFiles(Content c, List<MediaFile> mfs) {
    	if (c.getStatus().equals(Constants.CONTENT_STATUS_DELETE)) {
        	return;
        }
    	
        List<MediaFile> list = mediaFileService.findByContentId(c.getContentId());
        if (list != null && list.size() > 0) {
            mediaFileService.deleteByContentId(c.getContentId());
        }
        log.info("主流程|媒体文件存入DB：" + JSONUtil.toJsonStr(mfs));
        if (mfs != null && mfs.size() > 0) {
        	mediaFileService.saveAll(mfs);
        }
    }
    
    /**
     * <p><b>Title:</b> updateSecondClassifys</p>
     * <p><b>Description:</b> 更新二级分类列表</p>
     * @author douzi
     * @param c
     * @param scs
     */
    private void updateSecondClassifys(Content c, List<SecondClassify> scs) {
        List<SecondClassify> list = secondClassifyService.findAllByContentId(c.getContentId());
        if (list != null && list.size() > 0) {
            secondClassifyService.deleteByContentId(c.getContentId());
        }
        log.info("主流程|二级分类存入DB：" + JSONUtil.toJsonStr(scs));
        if (scs != null && scs.size() > 0) {
        	secondClassifyService.saveAll(scs);
        }
    }

	/**
	 * <p><b>Title:</b> judgeContent</p>
	 * <p><b>Description:</b> 校验内容是否合法；1.图片是否存在；2.媒体文件是否存在;</p>
	 * 1.1 除了直播内容以外，所有内容必须有一张图片
	 * @author douzi
	 * @param st
	 * @param c
	 */
	private void checkContent(SyncTask st, Content c) {
		boolean isAvail = true;
		StringBuffer failReason = new StringBuffer();
        if (!st.getOprCode().equals(Constants.SYNC_POMS_OPRCODE_CONTENT_DELETE)) {
        	//1.判断图片是否存在
            isAvail = checkPics(st, c, failReason);
        	//2.判断媒体文件是否存在
            isAvail = isAvail && checkMedias(st, c, failReason);
            
            //3.根据报错，终端流程，回执上游
            if (!isAvail) {
                st.setFailReason("SYNC_CONTENT_ERROR:" + failReason.toString());
                throw new BusinessException(MessageCodes.M989901, st.getFailReason());
            }
        }
	}

	/**
	 * <p><b>Title:</b> checkPics</p>
	 * <p><b>Description:</b> 判断图片是否存在</p>
	 * @author douzi
	 * @param st
	 * @param c
	 * @param localPath
	 * @param failReason
	 * @param type
	 */
	private boolean checkPics(SyncTask st, Content c, StringBuffer failReason) {
		String localPath = systemConfigService.findAllBykey("syncFile_basePath").getValue() 
				+ "/" + st.getBasePath() + "/" + st.getContentId();
    	String type = c.getType();
		if (type != null && !type.equals("2") && !type.equals("5") 
				&& !type.equals("8") && !type.equals("9") && !type.equals("12")) {
			if (c.getDisplayFileList() == null || c.getDisplayFileList().size() == 0) {//所有内容必须有图片
			    log.error("内容同步主流程|业务数据：" + c.getContentId() + "|媒资id：" + st.getAccessId() + "元数据文件中无图片");
			    failReason.append("content[" + c.getContentId() + "] no pictures").append(";");
			    return false;
			} else if (c.getDisplayFileList().size() > 0) {
			    for (int i = 0; i < c.getDisplayFileList().size(); i++) {
			        DisplayFileFromXml df = c.getDisplayFileList().get(i);
			        String imgPath = localPath + "/display/" + df.getDpFileName();
			        File f = new File(imgPath);
			        if (!f.exists()) {
			        	log.error("内容同步主流程|业务数据：" + c.getContentId() + "|媒资id：" + st.getAccessId() + "原图片[" + imgPath + "]不存在");
			        	failReason.append("内容[" + c.getContentId() + "]原图片[" + imgPath + "]不存在").append(";");
			        	return false;
			        }
			        
			    }
			}
		} else {
		    log.info("内容同步主流程|业务数据：" + c.getContentId() + "|媒资id：" + st.getAccessId() + "为直播内容，无需判断是否有图");
		}
		return true;
	}

	/**
	 * <p><b>Title:</b> checkMedias</p>
	 * <p><b>Description:</b> 判断媒体文件是否存在</p>
	 * @author douzi
	 * @param st
	 * @param c
	 * @param platTypes
	 * @param failReason
	 */
	private boolean checkMedias(SyncTask st, Content c, StringBuffer failReason) {
    	String platFormTypes = systemConfigService.findAllBykey("NEED_DIST_PLATFORM_TYPE").getValue();
    	log.info("内容同步主流程|业务数据：" + c.getContentId() + "|媒资id：" + st.getAssetId() + "|NEED_DIST_PLATFORM_TYPE:" + platFormTypes);
        String[] platTypes = platFormTypes.split(","); //89, 189
        
		boolean allowMediaNull = false;
		for (String platForm : platTypes) {//来自 89及189 平台允许媒体文件为空
		    if (platForm.equals(st.getAccessPlatformType())) {
		        allowMediaNull = true;
		        break;
		    }
		}
		
		//当内容为视频或者音频，并且不为剧集时，必须包含媒体文件
		if (!allowMediaNull) {
		    if (c.getCategory() != null && (c.getCategory().equals("1") || c.getCategory().equals("2")) 
		    		&& c.getFormType() != null && (!c.getFormType().equals("6") && !c.getFormType().equals("10"))) {
		        if (c.getMediaFileList() == null || c.getMediaFileList().size() == 0) {
		            log.info("内容同步主流程|业务数据：" + c.getContentId() + "|媒资id：" + st.getAssetId() + "无媒体文件");
		            failReason.append("内容[" + c.getContentId() + "]无媒体文件").append(";");
		            return false;
		        } else {
		            for (MediaFileFromXml mf : c.getMediaFileList()) {
		                if (mf.getMediaSize() == null || mf.getMediaSize().equals("")) {
		                    log.info("内容同步主流程|业务数据：" + c.getContentId() + "|媒资id：" + st.getAccessId() + 
		                    		"|媒体文件:" + mf.getMediaFileID() + "|文件大小为空");
		                    failReason.append("媒体文件[" + mf.getMediaFileID() + "]文件大小为空").append(";");
		                    return false;
		                }
		            }
		        }
		    }
		}
		return true;
	}
	
	public static void main(String[] args) {
		String formType = "6";
		boolean a = !formType.equals("6") || !formType.equals("10");
		System.out.println(a);
	}

	/**
	 * <p><b>Title:</b> tranXml</p>
	 * <p><b>Description:</b> xml转换java对象</p>
	 * @author douzi
	 * @param docStr
	 * @return
	 * @throws IOException
	 * @throws JsonParseException
	 * @throws JsonMappingException
	 */
	private ContentFromXml tranXml(String docStr) throws IOException, JsonParseException, JsonMappingException {
		//配置xml转对象的参数
        XmlMapper xmlMapper = new XmlMapper();
        xmlMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        xmlMapper.configure(SerializationFeature.WRAP_ROOT_VALUE, false);
        xmlMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        xmlMapper.setPropertyNamingStrategy(PropertyNamingStrategy.UPPER_CAMEL_CASE);
        xmlMapper.enable(MapperFeature.USE_STD_BEAN_NAMING);
        ContentFromXml cfx = xmlMapper.readValue(docStr, ContentFromXml.class);
        log.info("内容同步主流程|通过媒资xml转换得到ContentFromXml对象：" + JSONUtil.toJsonStr(cfx));
		return cfx;
	}
    
    /**
     * <p><b>Title:</b> cleanXml</p>
     * <p><b>Description:</b> 本不应该存在的代码，删除上游不合法的xml节点。
     * 例如：<MediaFileLists></MediaFileLists> | <MediaFileLists/>等没有子节点的list节点</p>
     * @author douzi
     * @return
     */
    public String cleanXml(SyncTask st) {
    	String fileName = systemConfigService.findAllBykey("syncFile_baseName").getValue();
		String localPath = systemConfigService.findAllBykey("syncFile_basePath").getValue() 
				+ "/" + st.getBasePath() + "/" + st.getContentId();
        String syncFile = localPath + "/" + fileName;
    	org.w3c.dom.Document doc = XmlUtil.readXML(new File(syncFile));
    	
    	org.w3c.dom.Element root = doc.getDocumentElement();
    	String[] selNodes = { "/Content/Keywords/Keyword", "/Content/MediaFileLists/MediaFile",
				"/Content/PropertyFileLists/PropertyFile", "/Content/DisPlayFileLists/DisPlayFile",
				"/Content/Labels/Label" };
		String[] delEles = { "Keywords", "MediaFileLists", "PropertyFileLists",
				"DisPlayFileLists", "Labels"};
		for (int i = 0; i < selNodes.length; i++) {
			NodeList nodes = XmlUtil.getNodeListByXPath(selNodes[i], doc);
			if (nodes.getLength() == 0) {
				NodeList nodeList = root.getElementsByTagName(delEles[i]);
				for (int j = 0; j < nodeList.getLength(); j++) {
					root.removeChild(nodeList.item(j));
				}
			}
		}
		return XmlUtil.toStr(doc);
    }
}
